--MAX31865.lua

if spi == nil or bit == nil then
    error("max31865 Lua requires the spi and bit libraries")
end

spi.setup(1, spi.MASTER, spi.CPOL_HIGH, spi.CPHA_HIGH, 8, 40)

local max31865 = {}

max31865.RUN = 1
max31865.STOP = 0
max31865.FOUR_WIRE = 0
max31865.THREE_WIRE = 1
max31865.TWO_WIRE = 0
max31865.FILTER_50 = 1
max31865.FILTER_60 = 0
max31865._A = 3.908300e-3
max31865._B = -5.77500e-7
max31865._C = -4.18301e-12
max31865._root_find_iterations = 5


local _CVD_root_finder = function(r0, R)
--The Callendar Van Dusen Equation for Platinum Based RTD Thermometers
--Newton's method root finder
    local T = 0
    local a, b, c = max31865._A, max31865._B , max31865._C
    local i = max31865._root_find_iterations
    for _ = 1,i do
        if T < 0 then
            local r = r0 * (1 + a*T + b*T*T + c*(T - 100)*T*T*T) - R
            local slope = r0 * (a + 2*b*T + 4*c*(T - 75)*T*T)
            T = T - r/slope
        else
            local r = r0 * (1 + a*T + b*T*T) - R
            local slope = r0 * (a + 2*b*T)
            T = T - r/slope
        end
    end
    return T
end

max31865.setup = function(CS, config)
    local t = {}
   
    --chip select gpio setup
    t._CS = CS
    gpio.mode(t._CS, gpio.OUTPUT)
    gpio.write(t._CS, gpio.HIGH)
   
    t._spi_transaction = function(self, write_data, read_bytes)
        spi.set_mosi(1, write_data)
        gpio.write(self._CS, 0)
        spi.transaction( 1, 0, 0, 0, 0, #write_data * 8, 0, read_bytes * 8)
        gpio.write(self._CS, 1)
        return spi.get_miso(1, read_bytes)
    end
   
    t._config = config or 0xd0  --0b11010000 default
    -- see: https://datasheets.maximintegrated.com/en/ds/MAX31865.pdf
    t.config = function(self, run_stop, wires, filter)
        if run_stop ~= nil then
            if run_stop == 1 then
                self._config = bit.set(self._config, 7)
                self._config = bit.set(self._config, 6)
            elseif run_stop == 0 then
                self._config = bit.clear(self._config, 7)
                self._config = bit.clear(self._config, 6)
            end
        end
        if wires ~= nil then
            if wires == 1 then
                self._config = bit.set(self._config, 4)
            elseif wires == 0 then
                self._config = bit.clear(self._config, 4)
            end
        end
        if filter ~= nil then
            if filter == 1 then
                self._config = bit.set(self._config, 0)
            elseif filter == 0 then
                self._config = bit.clear(self._config, 0)
            end
        end
        self:_spi_transaction('\128' .. string.char(self._config), 0)
    end
   
    t.adc = function(self)
        local raw = self:_spi_transaction('\1',2)
        return bit.rshift(string.byte(raw,1) * 256 + string.byte(raw, 2), 1)
    end
   
    t.resistance = function(self, Rref)
        Rref = Rref or 430
        return (self:adc() *  Rref) / 32768
    end
   
    --default zero point for ideal 100ohm PRT and ideal 430ohm burden resistor: 7620.5
    t.adc_zero = 7620.5
   
    t.temp = function(self)
        return _CVD_root_finder(self.adc_zero, self:adc())
    end
   
    t:config()
    return t
end


return max31865